'''
Created on 2009-10-5

@author: ray
'''
import Queue
from Host import *
from random import random
from WorkingThread import *

MAX_QSIZE  = 0   #Infinite message queue size by default

class MsgBuf(object):

    def __init__(self):
        self.version = 0
        self.host = Host()
        self.packetNo = 0L
        self.command = 0L
        self.exMsg = ""
        self.msg = ""


        
class MsgMng(object):


    def __init__(self, (nicAddr, portNo)):
        userName = os.environ["USERNAME"]
        if os.environ.has_key("COMPUTERNAME"):
            hostName = os.environ["COMPUTERNAME"]
        else:
            hostName = ""
        self.local = Host(userName, hostName, nicAddr, portNo)
        self._packetNo = long(random()*100000)
        self.msgQueue = Queue.Queue(MAX_QSIZE) # The Queue is thread-safe itself
        self.fileToSend = []
        self.lck = Lock()
        self.sockInit()

    def sockInit(self):
        self.udp_sd = socket(AF_INET, SOCK_DGRAM)
        self.tcp_sd = socket(AF_INET, SOCK_STREAM)
        self.udp_sd.bind((self.local.addr, self.local.portNo))
        self.tcp_sd.bind((self.local.addr, self.local.portNo))
        self.udp_sd.setsockopt(SOL_SOCKET, SO_BROADCAST, True)
        self.tcp_sd.listen(1)
        
    def addSendFile(self, (packetNo, files)):
        self.lck.acquire()
        self.fileToSend.append((packetNo, files))
        self.lck.release()
        
    def delSendFile(self,(packetNo, id)):
        self.lck.acquire()
        for i in self.fileToSend:
            if i[0] == packetNo:
                ret =  i[1][id]
                if ret != None:
                    i[1][id] = None
                    c = 0
                    for j in i[1]:
                        if j != None:
                            c += 1
                    if c == 0:
                        self.fileToSend.remove(i)
                break    
        self.lck.release()
        print ("remain:", self.fileToSend)
        return ret
    
    def makePacketNo(self):
        self._packetNo += 1
        return self._packetNo
    
    def makeMsg(self, command, msg, exMsg):
        packetNo = self.makePacketNo()
        buf = "%d:%ld:%s:%s:%ld:" %(IPMSG_VERSION, packetNo, self.local.userName, self.local.hostName, command)
        return packetNo, "".join((buf, msg, "\0", exMsg))

    def send(self, to, command, msg, exMsg):
        if isinstance(to, Host):
            addr = (to.addr, to.portNo)
        else:
            addr = to
        packetNo, buf = self.makeMsg(command, msg, exMsg)
        #print "You =",buf          #only for debug print
        self.udp_sd.sendto(buf, addr)
        return packetNo
    
    def tcpSend(self, sock, command, msg, exMsg):
        _, buf = self.makeMsg(command, msg, exMsg)
        #print ("buf=", buf)
        return sock.send(buf)
      
    def makeSendFileInfo(self, files):
        ''' Extra attr is not supported yet'''
        info = []
        for i, f in enumerate(files):
            id = i
            name = os.path.basename(f)
            size = getFileSize(f)
            mtime = long(time.time())   #modified later
            if os.path.isdir(f):
                type = IPMSG_FILE_DIR
            elif os.path.isfile(f):
                type = IPMSG_FILE_REGULAR
            info.append("%x:%s:%x:%x:%x:" %(id, name, size, mtime, type))
        return "\x07".join(info)
    
    def udpEvent(self, msg):
        '''Callback function invoked when msg arrives, 
        and should be overrided in its subclass, in this class debug print only '''
        print msg.host
        print "version =", msg.version
        print "command =", msg.command
        print "msg =", msg.msg
        print "exMsg = ", msg.exMsg
        
    def resolveMsg(self, data, addr):
        msgbuf = MsgBuf()

        v = data.split(":", 5)
        if len(v) < 6:
            return None
        msgbuf.host.addr = addr[0]
        msgbuf.host.portNo = addr[1]
        msgbuf.version = v[0]
        msgbuf.packetNo = long(v[1])
        msgbuf.host.userName = v[2]
        msgbuf.host.hostName = v[3]
        msgbuf.command = long(v[4])

        vv = v[5].split("\0", 1)
        if len(vv) >= 2:
            msgbuf.msg = vv[0]
            msgbuf.exMsg = vv[1]
        else:
            msgbuf.msg = v[5]
        return msgbuf

    def eventLoop(self):
        UDPThread(self).start()
        TCPThread(self).start()
        DispatchThread(self).start()

    def closeSocket(self):
        #self.tcp_sd.shutdown(2)
        self.udp_sd.close()
        self.tcp_sd.close()
